''' Tools for interacting with Weka .arff files.
    
    Copyright (C) 2013 Jerrad Michael Genson

    This program is free software: you can redistribute it and/or modify
    it under the terms of the BSD 3-Clause License as published by
    the Open Source Initiative.
    
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    BSD 3-Clause License for more details.
    
    You should have received a copy of the BSD 3-Clause License
    along with this program.  If not, see 
    <https://betelgeuse-ml.googlecode.com/hg/LICENSE>     
    '''

# Python built-in modules
import re

# Module header
__author__ = 'Jerrad Genson'
__contact__ = 'jerradgenson@gmail.com'
__copyright__ = 'Copyright 2013 Jerrad Michael Genson'
__license__ = 'BSD 3-Clause'


def parse(path):
    ''' Parse and load an attribute-relation (.arff) file.
        @param path The path to the .arff file.
        @return An AttributeRelation object.
        '''

    with open(path, 'r') as input_fd:
        relation = AttributeRelation()
        # Get relation name and attributes.
        try:
            for line in input_fd:
                if '@relation' in line:
                    # Found relation name.
                    relation.name = line.split('@relation')[1].strip()

                elif '@attribute' in line:
                    # Found relation attribute.
                    split_line = re.split('\s+', line)
                    attr = split_line[1].lower()
                    attr_type = split_line[2].lower()
                    relation.attributes.append(attr)
                    relation.attr_types.append(attr_type)

                elif '@data' in line:
                    # Start parsing data.
                    break

            for line in input_fd:
                relation.add_row()
                if re.search('\w', line):
                    # Parse line data
                    split_line = re.split(',\s{0,}', line)
                    for data in split_line:
                        relation.row.append(data.strip())

            if not relation.row:
                # Did not find any data.
                raise ValueError

        except (IndexError, ValueError):
            error = 'Parser error. File: {0}. '.format(path)
            error += 'Line: {0} '.format(line)
            raise ValueError(error)

    return relation

class AttributeRelation(object):
    ''' Manages an Attribute-Relation database.
        AttributeRelation objects can be indexed with a key.
        A key is a relation attribute, and the index will return
        the value in the current row corresponding to the given key.
        AttributeRelations are also iterable; each iteration will
        return an AttributeRelation object set to the next row, starting
        with the first row in the table.
        '''

    def __init__(self):
        self.name = ''
        self.attributes = []
        self.attr_types = []
        self.table = []
        self._row = None

    def add_row(self):
        '''Add an additional row to the table.'''

        self._row = []
        self.table.append(self._row)

    def __get_row(self):
        return self._row

    def __set_row(self, index):
        self._row = self.table[index]

    def __del_row(self):
        del self._row

    row = property(__get_row,
                   __set_row,
                   __del_row,
                   '''The current row in the database table.
                    Assign row to an integer to change the
                    current row. An IndexError exception will
                    be raised if assigned a non-existent row.''')

    def __getitem__(self, key):
        return self.row[self.attributes.index(key)]

    def __iter__(self):
        for row in self.table:
            self._row = row
            yield self

    def __len__(self):
        return len(self.table)

